home *** CD-ROM | disk | FTP | other *** search
/ System Booster / System Booster.iso / Archives / GNU / GNUPLOTsrc.lha / plot2d.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-01-30  |  45.4 KB  |  1,432 lines

  1. #ifndef lint
  2. static char    *RCSid = "$Id: plot2d.c,v 1.24 1995/12/12 22:10:47 drd Exp $";
  3. #endif
  4.  
  5.  
  6. /* GNUPLOT - plot2d.c */
  7. /*
  8.  * Copyright (C) 1986 - 1993   Thomas Williams, Colin Kelley
  9.  * 
  10.  * Permission to use, copy, and distribute this software and its documentation
  11.  * for any purpose with or without fee is hereby granted, provided that the
  12.  * above copyright notice appear in all copies and that both that copyright
  13.  * notice and this permission notice appear in supporting documentation.
  14.  * 
  15.  * Permission to modify the software is granted, but not the right to distribute
  16.  * the modified code.  Modifications are to be distributed as patches to
  17.  * released version.
  18.  * 
  19.  * This software is provided "as is" without express or implied warranty.
  20.  * 
  21.  * 
  22.  * formerly part of command.c
  23.  * 
  24.  * There is a mailing list for gnuplot users. Note, however, that the
  25.  * newsgroup 
  26.  *    comp.graphics.gnuplot 
  27.  * is identical to the mailing list (they
  28.  * both carry the same set of messages). We prefer that you read the
  29.  * messages through that newsgroup, to subscribing to the mailing list.
  30.  * (If you can read that newsgroup, and are already on the mailing list,
  31.  * please send a message info-gnuplot-request@dartmouth.edu, asking to be
  32.  * removed from the mailing list.)
  33.  *
  34.  * The address for mailing to list members is
  35.  *       info-gnuplot@dartmouth.edu
  36.  * and for mailing administrative requests is 
  37.  *       info-gnuplot-request@dartmouth.edu
  38.  * The mailing list for bug reports is 
  39.  *       bug-gnuplot@dartmouth.edu
  40.  * The list of those interested in beta-test versions is
  41.  *       info-gnuplot-beta@dartmouth.edu
  42.  */
  43.  
  44. #include <math.h>
  45. #include <ctype.h>
  46. #include <assert.h>
  47.  
  48. #ifdef AMIGA_AC_5
  49. void            sleep();    /* defined later */
  50. #endif
  51.  
  52. #ifdef VMS
  53. #include <signal.h>  /* for sleep() */
  54. #endif
  55.  
  56. #if defined(MSDOS) || defined(DOS386)
  57. #ifdef DJGPP
  58. #include <dos.h>
  59. #else
  60. #include <process.h>
  61. #endif
  62.  
  63. #ifdef __ZTC__
  64. #define P_WAIT 0
  65. #else
  66.  
  67. #ifdef __TURBOC__
  68. #ifndef _Windows
  69. #include <dos.h>        /* sleep() */
  70. #include <conio.h>
  71. #include <dir.h>    /* setdisk() */
  72. #endif
  73.  
  74. #else                /* must be MSC */
  75. #if !defined(__EMX__) && !defined(DJGPP)
  76. #ifdef __MSC__
  77. #include <direct.h>        /* for _chdrive() */
  78. #endif
  79. void            sleep();    /* defined later */
  80. #endif                /* !__EMX__ && !DJGPP */
  81. #endif                /* TURBOC */
  82. #endif                /* ZTC */
  83.  
  84. #endif                /* MSDOS */
  85.  
  86. #ifdef AMIGA_SC_6_1
  87. #include <proto/dos.h>
  88. void            sleep();
  89. #endif                /* AMIGA_SC_6_1 */
  90.  
  91. #include "plot.h"
  92. #include "setshow.h"
  93. #include "fit.h"
  94. #include "binary.h"
  95. #ifndef _Windows
  96. #include "help.h"
  97. #else
  98. #define MAXSTR 255
  99. #endif
  100.  
  101. #if defined(ATARI) || defined(MTOS)
  102. #ifdef __PUREC__
  103. #include <ext.h>
  104. #include <tos.h>
  105. #include <aes.h>
  106. #include <float.h>        /* get FLT_MAX */
  107. #else
  108. #include <osbind.h>
  109. #include <aesbind.h>
  110. #endif /* __PUREC__ */
  111. #endif /* ATARI || MTOS */
  112.  
  113. #ifndef STDOUT
  114. #define STDOUT 1
  115. #endif
  116.  
  117.  
  118.  
  119. #define inrange(z,min,max) ((min<max) ? ((z>=min)&&(z<=max)) : ((z>=max)&&(z<=min)) )
  120.  
  121. /* static prototypes */
  122.  
  123. void plotrequest __P((void));
  124. void plot3drequest __P((void));
  125. void define __P((void));
  126. static void get_data __P((struct curve_points *this_plot));
  127. static void store2d_point __P((struct curve_points *this_plot, int i, double x, double y, double xlow, double xhigh, double ylow, double yhigh, double width));
  128. static void print_table __P((struct curve_points *first_plot, int plot_num));
  129. static void eval_plots __P((void));
  130. static void parametric_fixup __P((struct curve_points *start_plot, int *plot_num));
  131.  
  132.  
  133. /* the curves/surfaces of the plot */
  134. struct curve_points *first_plot = NULL;
  135. static struct udft_entry plot_func;
  136. extern struct udft_entry *dummy_func;
  137.  
  138. /* jev -- for passing data thru user-defined function */
  139. /* static */ struct udft_entry ydata_func;  /* datafile.c needs access */
  140.  
  141. extern int datatype[];
  142. extern char timefmt[];
  143.  
  144. extern TBOOLEAN is_3d_plot;
  145. extern int plot_token;
  146.  
  147. /* in order to support multiple axes, and to
  148.  * simplify ranging in parametric plots, we use
  149.  * arrays to store some things.
  150.  * Elements are z=0,y1=1,x1=2, [z2=4], y2=5, x2=6
  151.  * these are given symbolic names in plot.h
  152.  */
  153.  
  154. extern double          min_array[AXIS_ARRAY_SIZE], max_array[AXIS_ARRAY_SIZE];
  155. extern int             auto_array[AXIS_ARRAY_SIZE];
  156. extern TBOOLEAN        log_array[AXIS_ARRAY_SIZE];
  157. extern double          base_array[AXIS_ARRAY_SIZE];
  158. extern double          log_base_array[AXIS_ARRAY_SIZE];
  159.  
  160. /* if user specifies [10:-10] we use [-10:10] internally, and swap at end */
  161. int reverse_range[AXIS_ARRAY_SIZE];
  162.  
  163. /* info from datafile module */
  164. extern int df_datum;
  165. extern int df_line_number;
  166. extern int df_no_use_specs;
  167. extern int df_eof;
  168. extern int df_timecol[];
  169. extern TBOOLEAN df_binary;
  170.  
  171. #ifndef min
  172. #define min(a,b)    ((a)>(b) ? (b) : (a))
  173. #endif
  174. #define Inc_c_token if (++c_token >= num_tokens)    \
  175.                         int_error ("Syntax error", c_token);
  176.  
  177.  
  178. /*
  179.  * IMHO, code is getting too cluttered with repeated chunks of
  180.  * code. Some macros to simplify, I hope.
  181.  *
  182.  * do { } while(0) is comp.lang.c recommendation for complex macros
  183.  * also means that break can be specified as an action, and it will
  184.  * 
  185.  */
  186.  
  187. /*  copy scalar data to arrays
  188.  * optimiser should optimise infinite away
  189.  * dont know we have to support ranges [10:-10] - lets reverse
  190.  * it for now, then fix it at the end.
  191.  */
  192. #define INIT_ARRAYS(axis, min, max, auto, is_log, base, log_base, infinite) \
  193. do{auto_array[axis]=auto; \
  194.    min_array[axis]=(infinite && (auto&1)) ? VERYLARGE : min; \
  195.    max_array[axis]=(infinite && (auto&2)) ? -VERYLARGE : max; \
  196.    log_array[axis]=is_log; base_array[axis]=base; log_base_array[axis]=log_base;\
  197. }while(0)
  198. /* handle reversed ranges */
  199. #define CHECK_REVERSE(axis) \
  200. do{\
  201.  if (auto_array[axis]==0 && max_array[axis] < min_array[axis]) {\
  202.   double temp=min_array[axis]; min_array[axis]=max_array[axis]; max_array[axis]=temp;\
  203.   reverse_range[axis]=1; \
  204.  } else reverse_range[axis] = (range_flags[axis]&RANGE_REVERSE); \
  205. }while(0)
  206.  
  207.  
  208. /* get optional [min:max] */
  209. #define LOAD_RANGE(axis) \
  210. do {\
  211.  if (equals(c_token, "[")) { \
  212.   c_token++; \
  213.   auto_array[axis] = load_range(axis,&min_array[axis], &max_array[axis], auto_array[axis]);\
  214.   if (!equals(c_token, "]"))\
  215.    int_error("']' expected", c_token);\
  216.   c_token++;\
  217.  }\
  218. } while (0)
  219.  
  220.  
  221. /* store VALUE or log(VALUE) in STORE, set TYPE as appropriate
  222.  * Do OUT_ACTION or UNDEF_ACTION as appropriate
  223.  * adjust range provided type is INRANGE (ie dont adjust y if x is outrange
  224.  * VALUE must not be same as STORE
  225.  */
  226.  
  227. #define STORE_WITH_LOG_AND_FIXUP_RANGE(STORE, VALUE, TYPE, AXIS, OUT_ACTION, UNDEF_ACTION)\
  228. do { if (log_array[AXIS]) { if (VALUE<0.0) {TYPE=UNDEFINED; UNDEF_ACTION; break;} \
  229.               else if (VALUE==0.0){STORE=-VERYLARGE; TYPE=OUTRANGE; OUT_ACTION; break;} \
  230.               else { STORE=log(VALUE)/log_base_array[AXIS]; } \
  231.      } else STORE=VALUE; \
  232.      if (TYPE != INRANGE) break;  /* dont set y range if x is outrange, for example */ \
  233.      if ( VALUE<min_array[AXIS] ) \
  234.       if (auto_array[AXIS] & 1) min_array[AXIS]=VALUE; else { TYPE=OUTRANGE; OUT_ACTION; break; }  \
  235.      if ( VALUE>max_array[AXIS] ) \
  236.      if (auto_array[AXIS] & 2) max_array[AXIS]=VALUE; else { TYPE=OUTRANGE; OUT_ACTION; }   \
  237. } while(0)
  238.      
  239. /* use this instead empty macro arguments to work around NeXT cpp bug */
  240. /* if this fails on any system, we might use ((void)0) */
  241. #define NOOP /* */
  242.  
  243. /* check axis range is not too small -
  244.  * extend if you can (autoscale), else report error
  245.  */
  246. #ifdef ANSI_C
  247. # define STRINGIFY(x) #x 
  248. # define RANGE_MSG(x) #x " range is less than `zero`"
  249. # define LOG_MSG(x) #x " range must be greater than 0 for log scale!"
  250. #else
  251. # define STRINGIFY(x) "x"
  252. # define RANGE_MSG(x) "x range is less than `zero`"
  253. # define LOG_MSG(x) "x range must be greater than 0 for log scale!"
  254. #endif
  255.  
  256. #define FIXUP_RANGE(AXIS, WHICH) \
  257. do{if (fabs(max_array[AXIS] - min_array[AXIS]) < zero)    \
  258.     if (auto_array[AXIS]) { /* widen range */  \
  259.      fprintf(stderr, "Warning: empty %s range [%g:%g], ", STRINGIFY(WHICH), min_array[AXIS], max_array[AXIS]);      \
  260.      if (fabs(min_array[AXIS]) < zero) { \
  261.       if (auto_array[AXIS] & 1) min_array[AXIS] = -1.0; \
  262.       if (auto_array[AXIS] & 2) max_array[AXIS] = 1.0;   \
  263.      } else if (max_array[AXIS] < 0) { \
  264.       if (auto_array[AXIS] & 1) min_array[AXIS] *= 1.1; if (auto_array[AXIS] & 2) max_array[AXIS] *= 0.9;    \
  265.      } else { if (auto_array[AXIS] & 1) min_array[AXIS] *= 0.9; if (auto_array[AXIS] & 2) max_array[AXIS] *= 1.1;  }  \
  266.      fprintf(stderr, "adjusting to [%g:%g]\n", min_array[AXIS], max_array[AXIS]);          \
  267.     } else int_error(RANGE_MSG(WHICH), c_token);   \
  268. }while(0)
  269.  
  270. /* check range and take logs of min and max if logscale
  271.  * this also restores min and max for ranges like [10:-10]
  272.  */
  273.  
  274. #define FIXUP_RANGE_FOR_LOG(AXIS, WHICH) \
  275. do { if (reverse_range[AXIS]) { \
  276.       double temp = min_array[AXIS]; \
  277.       min_array[AXIS]=max_array[AXIS]; \
  278.       max_array[AXIS]=temp; \
  279.      }\
  280.      if (log_array[AXIS]) { \
  281.       if (min_array[AXIS]<=0.0 || max_array[AXIS]<=0.0) \
  282.        int_error(LOG_MSG(WHICH), NO_CARET); \
  283.       min_array[AXIS] = log(min_array[AXIS])/log_base_array[AXIS]; \
  284.       max_array[AXIS] = log(max_array[AXIS])/log_base_array[AXIS];  \
  285. } } while(0)
  286.  
  287.  
  288.  
  289. void plotrequest()
  290. /*
  291.  * In the parametric case we can say plot [a= -4:4] [-2:2] [-1:1] sin(a),a**2
  292.  * while in the non-parametric case we would say only plot [b= -2:2] [-1:1]
  293.  * sin(b)
  294.  */
  295. {
  296.     int             dummy_token = -1;
  297.  
  298.     if (!term)            /* unknown */
  299.     int_error("use 'set term' to set terminal type first", c_token);
  300.  
  301.     is_3d_plot = FALSE;
  302.  
  303.     if (parametric && strcmp(dummy_var[0], "u") == 0)
  304.     strcpy(dummy_var[0], "t");
  305.  
  306.     /* initialise the arrays from the 'set' scalars */
  307.      
  308.     INIT_ARRAYS(FIRST_X_AXIS, xmin, xmax, autoscale_x, is_log_x, base_log_x, log_base_log_x, 0);
  309.     INIT_ARRAYS(FIRST_Y_AXIS, ymin, ymax, autoscale_y, is_log_y, base_log_y, log_base_log_y, 1);
  310.     INIT_ARRAYS(SECOND_X_AXIS, x2min, x2max, autoscale_x2, is_log_x2, base_log_x2, log_base_log_x2, 0);
  311.     INIT_ARRAYS(SECOND_Y_AXIS, y2min, y2max, autoscale_y2, is_log_y2, base_log_y2, log_base_log_y2, 1);
  312.  
  313.     min_array[T_AXIS]=tmin; max_array[T_AXIS]=tmax;
  314.  
  315.     if (equals(c_token, "[")) {
  316.     c_token++;
  317.     if (isletter(c_token)) {
  318.         if (equals(c_token + 1, "=")) {
  319.         dummy_token = c_token;
  320.         c_token += 2;
  321.         } else {
  322.         /* oops; probably an expression with a variable. */
  323.         /* Parse it as an xmin expression. */
  324.         /* used to be: int_error("'=' expected",c_token); */
  325.         }
  326.     }
  327.     
  328.     {   int axis=(parametric||polar) ? T_AXIS : FIRST_X_AXIS;
  329.  
  330.  
  331.         auto_array[axis] = load_range(axis,&min_array[axis], &max_array[axis], auto_array[axis]);
  332.         if (!equals(c_token, "]"))
  333.         int_error("']' expected", c_token);
  334.         c_token++;
  335.     } /* end of scope of 'axis' */
  336.     } /* first '[' */
  337.     
  338.  
  339.     
  340.     if (parametric||polar)    /* set optional x ranges */
  341.     LOAD_RANGE(FIRST_X_AXIS);
  342.     else {
  343.      /* order of t doesn't matter, but x does */
  344.     CHECK_REVERSE(FIRST_X_AXIS);
  345.     }
  346.  
  347.     LOAD_RANGE(FIRST_Y_AXIS);
  348.     CHECK_REVERSE(FIRST_Y_AXIS);
  349.     LOAD_RANGE(SECOND_X_AXIS);
  350.     CHECK_REVERSE(SECOND_X_AXIS);
  351.     LOAD_RANGE(SECOND_Y_AXIS);
  352.     CHECK_REVERSE(SECOND_Y_AXIS);
  353.  
  354.     /* use the default dummy variable unless changed */
  355.     if (dummy_token >= 0)
  356.     copy_str(c_dummy_var[0], dummy_token, MAX_ID_LEN);
  357.     else
  358.     (void) strcpy(c_dummy_var[0], dummy_var[0]);
  359.  
  360.     eval_plots();
  361. }
  362.  
  363. #define NCOL 7          /* Use up to 7 columns in data file at once --
  364.                            originally it was 5 */
  365.  
  366.  
  367. static void get_data(this_plot)
  368. struct curve_points *this_plot;
  369. /* this_plot->token is after datafile spec, for error reporting
  370.  * it will later be moved passed title/with/linetype/pointtype
  371.  */
  372. {
  373.     register int    i /* no points ! */, j,col;
  374.     double v[NCOL];
  375.     int storetoken=this_plot->token;
  376.  
  377.     /* eval_plots has already opened file */
  378.  
  379.     switch(this_plot->plot_style){            /* set maximum columns to scan */
  380.         case XYERRORBARS:
  381.         case BOXXYERROR:  
  382.             col = 7; 
  383.             break;
  384.  
  385.         case BOXERROR:    
  386.             col = 5; 
  387.             break;
  388.  
  389.         case XERRORBARS:
  390.         case YERRORBARS:
  391.         case VECTOR:
  392.             col = 4; 
  393.             break;
  394.  
  395.         case BOXES:       
  396.             col = 3; 
  397.             break;
  398.  
  399.         default:          
  400.             col = 2;
  401.     }
  402.  
  403.     if (this_plot->plot_smooth == ACSPLINES)
  404.       col = 3;
  405.  
  406.     if (df_no_use_specs > col)
  407.         fprintf(stderr, "warning : too many using specs for this style\n");
  408.  
  409.     i = 0;
  410.     while ( (j = df_readline(v, col)) != DF_EOF)  {
  411.         /* j <= col */
  412.  
  413.         if (i >= this_plot->p_max) {
  414.             /*
  415.              * overflow about to occur. Extend size of points[] array. We
  416.              * either double the size, or add 1000 points, whichever is a
  417.              * smaller increment. Note i=p_max.
  418.              */
  419.             cp_extend(this_plot, i + (i < 1000 ? i : 1000));
  420.         }
  421.  
  422.  
  423.         /* Limitation: No xerrorbars with boxes */
  424.         switch (j) {
  425.         default:
  426.             {    char message[80];
  427.                 sprintf(message, "internal error : df_readline returned %d : datafile line %d", j, df_line_number);
  428.                 df_close();
  429.                 int_error(message, c_token);
  430.             }
  431.         case DF_UNDEFINED:
  432.             /* bad result from extended using expression */
  433.             this_plot->points[i].type = UNDEFINED;
  434.             i++;
  435.             continue;
  436.  
  437.         case DF_FIRST_BLANK:
  438.             /* break in data, make next point undefined */
  439.             this_plot->points[i].type = UNDEFINED;
  440.             i++;
  441.             continue;
  442.  
  443.         case DF_SECOND_BLANK:
  444.             /* second blank line. We dont do anything
  445.              * (we did everything when we got FIRST one)
  446.              */
  447.              continue;
  448.         
  449.         case 0: /* not blank line, but df_readline couldn't parse it */
  450.             {
  451.                 char message[80];
  452.                 sprintf(message, "Bad data on line %d", df_line_number);
  453.                 df_close();
  454.                 int_error(message, this_plot->token);
  455.             }
  456.             
  457.         case 1:
  458.             {        /* only one number */
  459.                 /* x is index, assign number to y */
  460.                 v[1]=v[0];
  461.                 v[0]=df_datum;
  462.                 /* nobreak */
  463.             }
  464.         case 2: 
  465.             {        /* x, y */
  466.                 /* ylow and yhigh are same as y */
  467.                 /* xlow and xhigh are same as x */
  468.                 store2d_point(this_plot, i++, v[0], v[1], v[0], v[0], v[1], v[1], -1.0);
  469.                 break;
  470.             }
  471.         case 3:
  472.             {    /* x, y, ydelta OR x, y, xdelta OR x, y, width */
  473.                 if(this_plot->plot_smooth == ACSPLINES)
  474.                         store2d_point(this_plot, i++, v[0], v[1], v[0], v[0], v[1], v[1], v[2]);
  475.                 else if(this_plot->plot_style == XERRORBARS)
  476.                     store2d_point(this_plot, i++, v[0], v[1], v[0]-v[2], v[0]+v[2], v[1], v[1], -1.0);
  477.                     /* xdelta is in the xlow variable */
  478.                 else if(this_plot->plot_style == BOXES)
  479.                     store2d_point(this_plot, i++, v[0], v[1], v[0], v[0], v[1], v[1], v[2]);
  480.                     /* width is in xlow variable */
  481.                 else if(this_plot->plot_style == YERRORBARS)
  482.                     store2d_point(this_plot, i++, v[0], v[1], v[0], v[0], v[1]-v[2], v[1]+v[2], -1.0);
  483.                     /* ydelta is in the xlow variable */
  484.                 else if(this_plot->plot_style == BOXERROR)
  485.                     store2d_point(this_plot, i++, v[0], v[1], v[0],v[0], v[1]-v[2], v[1]+v[2], -1.0);
  486.                 else {
  487.                     int_warn("This plot style not work with 3 cols. Setting to yerrorbars", storetoken);
  488.                     this_plot->plot_style = YERRORBARS;
  489.                     store2d_point(this_plot, i++, v[0], v[1], v[0], v[0], v[1]-v[2], v[1]+v[2], -1.0);
  490.                 }
  491.                 break;
  492.             }
  493.         case 4:
  494.             {
  495.                 /* x, y, ylow, yhigh OR
  496.                  * x, y, xlow, xhigh OR
  497.                  * x, y, xdelta, ydelta OR
  498.                  * x, y, ydelta, width
  499.                  */
  500.                 if(this_plot->plot_style == XERRORBARS)
  501.                     store2d_point(this_plot, i++, v[0], v[1], v[2], v[3], v[1], v[1], -1.0);
  502.                 else if((this_plot->plot_style == XYERRORBARS) ||
  503.                     (this_plot->plot_style == BOXXYERROR))
  504.                     store2d_point(this_plot, i++, v[0], v[1], v[0]-v[2], v[0]+v[2], v[1]-v[3], v[1]+v[3],
  505.                         -1.0);
  506.                     /* xdelta & ydelta are in xlow and xhigh variables */
  507.                 else if(this_plot->plot_style == BOXERROR){
  508.                     if(boxwidth == -2.0)
  509.                         store2d_point(this_plot, i++, v[0], v[1], v[0],v[0], v[1]-v[2], v[1]+v[2],
  510.                             -1.0);
  511.                     else
  512.                         store2d_point(this_plot, i++, v[0], v[1], v[0],v[0], v[1]-v[2], v[1]+v[2],
  513.                             v[3]);
  514.                 }
  515.                 /* ydelta & width are in xlow and xhigh variables */
  516.                 else if(this_plot->plot_style ==VECTOR)
  517.                     store2d_point(this_plot, i++, v[0], v[1], v[0], v[0]+v[2], v[1], v[1]+v[3], -1.0);
  518.                 else if(this_plot->plot_style == YERRORBARS)
  519.                     store2d_point(this_plot, i++, v[0], v[1], v[0], v[0], v[2], v[3], -1.0);
  520.                     /* ylow and yhigh are in xlow and xhigh variables */
  521.                 else {
  522.                     int_warn("This plot style not work with 4 cols. Setting to yerrorbars",
  523.                         storetoken);
  524.                     this_plot->plot_style = YERRORBARS;
  525.                     store2d_point(this_plot, i++, v[0], v[1], v[0], v[0], v[2], v[3], -1.0);
  526.                 }
  527.                 break;
  528.             }
  529.         case 5: 
  530.             {        /* x, y, ylow, yhigh, width */
  531.                 if(this_plot->plot_style != BOXERROR){
  532.                     int_warn("Five col. plot style must be boxerrorbars. Setting to boxerrorbars", storetoken);
  533.                     this_plot->plot_style = BOXERROR;
  534.                 }
  535.                 store2d_point(this_plot, i++, v[0], v[1], v[0], v[0], v[2], v[3], v[4]);
  536.                 break;
  537.             }
  538.         case 6: 
  539.             {           /* x, y, xlow, xhigh, ylow, yhigh */
  540.                 if(this_plot->plot_style != BOXXYERROR &&
  541.                     this_plot->plot_style != XYERRORBARS){
  542.                     int_warn("This plot style not work with 6 cols. Setting to xyerrorbars",storetoken);
  543.                     this_plot->plot_style = XYERRORBARS;
  544.                 }
  545.                 store2d_point(this_plot, i++, v[0], v[1], v[2], v[3], v[4], v[5], -1.0);
  546.                 break;
  547.             }
  548.         case 7: 
  549.             {   /* same as six columns. Width ignored */
  550.                 if(this_plot->plot_style != BOXXYERROR &&
  551.                     this_plot->plot_style != XYERRORBARS){
  552.                     int_warn("This plot style not work with 7 cols. Setting to xyerrorbars",
  553.                         storetoken);
  554.                     this_plot->plot_style = XYERRORBARS;
  555.                 }
  556.                 store2d_point(this_plot, i++, v[0], v[1], v[2], v[3], v[4], v[5], -1.0);
  557.                 break;
  558.             }
  559.         }
  560.     }
  561.     this_plot->p_count = i;
  562.     cp_extend(this_plot, i);    /* shrink to fit */
  563.  
  564.     df_close();
  565. }
  566.  
  567. /* called by get_data for each point */
  568. static void store2d_point(this_plot, i, x, y, xlow, xhigh, ylow, yhigh, width)
  569.     struct curve_points *this_plot;
  570.     int             i;        /* point number */
  571.     double          x, y;
  572.     double          ylow, yhigh;
  573.     double          xlow, xhigh;
  574.     double          width;
  575. {
  576.     struct coordinate GPHUGE *cp = &(this_plot->points[i]);
  577.     int dummy_type=INRANGE; /* sometimes we dont care about outranging */
  578.  
  579.  
  580.     /* jev -- pass data values thru user-defined function */
  581.     /* div -- y is dummy variable 2 - copy value there */
  582.     if (ydata_func.at) {
  583.     struct value    val;
  584.  
  585.     (void) Gcomplex(&ydata_func.dummy_values[0], y, 0.0);
  586.     ydata_func.dummy_values[2] = ydata_func.dummy_values[0];
  587.     evaluate_at(ydata_func.at, &val);
  588.     y = real(&val);
  589.  
  590.     (void) Gcomplex(&ydata_func.dummy_values[0], ylow, 0.0);
  591.     ydata_func.dummy_values[2] = ydata_func.dummy_values[0];
  592.     evaluate_at(ydata_func.at, &val);
  593.     ylow = real(&val);
  594.  
  595.     (void) Gcomplex(&ydata_func.dummy_values[0], yhigh, 0.0);
  596.     ydata_func.dummy_values[2] = ydata_func.dummy_values[0];
  597.     evaluate_at(ydata_func.at, &val);
  598.     yhigh = real(&val);
  599.     }
  600.  
  601.     dummy_type = cp->type=INRANGE;
  602.  
  603.     if (polar) {
  604.         double newx, newy;
  605.     if ( !(autoscale_r&2) && y>rmax)
  606.         cp->type=OUTRANGE;
  607.     if ( !(autoscale_r&1) )
  608.         y -= rmin; /* we store internally as if plotting r(t)-rmin */
  609.     newx = y*cos(x * ang2rad);
  610.     newy = y*sin(x * ang2rad);
  611.     y = ylow = yhigh = newy; /* only lines and points supported with polar */
  612.     x = xlow = xhigh = newx;
  613.     }
  614.  
  615.     /* return immediately if x or y are undefined
  616.      * we dont care if outrange for high/low.
  617.      * BUT if high/low undefined (ie log( < 0 ), no number is stored, but graphics.c doesn't know.
  618.      * explicitly store -VERYLARGE;
  619.      */
  620.     STORE_WITH_LOG_AND_FIXUP_RANGE(cp->x, x, cp->type, this_plot->x_axis, NOOP, return );
  621.     STORE_WITH_LOG_AND_FIXUP_RANGE(cp->xlow, xlow, dummy_type, this_plot->x_axis, NOOP, cp->xlow=-VERYLARGE);
  622.     STORE_WITH_LOG_AND_FIXUP_RANGE(cp->xhigh, xhigh, dummy_type, this_plot->x_axis, NOOP, cp->xhigh=-VERYLARGE);
  623.     STORE_WITH_LOG_AND_FIXUP_RANGE(cp->y, y, cp->type, this_plot->y_axis, NOOP, return );
  624.     STORE_WITH_LOG_AND_FIXUP_RANGE(cp->ylow, ylow, dummy_type, this_plot->y_axis, NOOP,cp->ylow=-VERYLARGE);
  625.     STORE_WITH_LOG_AND_FIXUP_RANGE(cp->yhigh, yhigh, dummy_type, this_plot->y_axis, NOOP,cp->yhigh=-VERYLARGE);
  626.     cp->z = width;
  627. } /* store2d_point */
  628.  
  629.  
  630.  
  631. /*
  632.  * print_points: a debugging routine to print out the points of a curve, and
  633.  * the curve structure. If curve<0, then we print the list of curves.
  634.  */
  635.  
  636. #if 0 /* not used */
  637. static char    *plot_type_names[4] =
  638. {
  639.     "Function", "Data", "3D Function", "3d data"
  640. };
  641. static char    *plot_style_names[14] =
  642. {
  643.     "Lines", "Points", "Impulses", "LinesPoints", "Dots", "XErrorbars",
  644.     "YErrorbars", "XYErrorbars", "BoxXYError", "Boxes", "Boxerror", "Steps",
  645.     "FSteps", "Vector"
  646. };
  647. static char    *plot_smooth_names[5] =
  648. {
  649.     "None", "Unique", "CSplines", "ACSplines", "Bezier", "SBezier"
  650. };
  651.  
  652. static void print_points(curve)
  653.     int             curve;    /* which curve to print */
  654. {
  655.     register struct curve_points *this_plot;
  656.     int             i;
  657.  
  658.     if (curve < 0) {
  659.     for (this_plot = first_plot, i = 0;
  660.          this_plot != NULL;
  661.          i++, this_plot = this_plot->next_cp) {
  662.         printf("Curve %d:\n", i);
  663.         if ((int) this_plot->plot_type >= 0 && (int) (this_plot->plot_type) < 4)
  664.         printf("Plot type %d: %s\n", (int) (this_plot->plot_type),
  665.                plot_type_names[(int) (this_plot->plot_type)]);
  666.         else
  667.         printf("Plot type %d: BAD\n", (int) (this_plot->plot_type));
  668.         if ((int) this_plot->plot_style >= 0 && (int) (this_plot->plot_style) < 14)
  669.         printf("Plot style %d: %s\n", (int) (this_plot->plot_style),
  670.                plot_style_names[(int) (this_plot->plot_style)]);
  671.         else
  672.         printf("Plot style %d: BAD\n", (int) (this_plot->plot_style));
  673.         if ((int) this_plot->plot_smooth >= 0 && (int) (this_plot->plot_smooth) < 6)
  674.         printf("Plot smooth style %d: %s\n", (int) (this_plot->plot_style),
  675.                plot_smooth_names[(int) (this_plot->plot_smooth)]);
  676.         else
  677.         printf("Plot smooth style %d: BAD\n", (int) (this_plot->plot_smooth));
  678.         printf("Plot title: '%s'\n", this_plot->title);
  679.         printf("Line type %d\n", this_plot->line_type);
  680.         printf("Point type %d\n", this_plot->point_type);
  681.         printf("max points %d\n", this_plot->p_max);
  682.         printf("current points %d\n", this_plot->p_count);
  683.         printf("\n");
  684.     }
  685.     } else {
  686.     for (this_plot = first_plot, i = 0;
  687.          i < curve && this_plot != NULL;
  688.          i++, this_plot = this_plot->next_cp);
  689.     if (this_plot == NULL)
  690.         printf("Curve %d does not exist; list has %d curves\n", curve, i);
  691.     else {
  692.         printf("Curve %d, %d points\n", curve, this_plot->p_count);
  693.         for (i = 0; i < this_plot->p_count; i++) {
  694.                 printf("%c x=%g y=%g z=%g xlow=%g xhigh=%g ylow=%g yhigh=%g\n",
  695.                this_plot->points[i].type == INRANGE ? 'i'
  696.                : this_plot->points[i].type == OUTRANGE ? 'o'
  697.                : 'u',
  698.                this_plot->points[i].x,
  699.                this_plot->points[i].y,
  700.                this_plot->points[i].z,
  701.                        this_plot->points[i].xlow,
  702.                        this_plot->points[i].xhigh,
  703.                this_plot->points[i].ylow,
  704.                this_plot->points[i].yhigh);
  705.         }
  706.         printf("\n");
  707.     }
  708.     }
  709. }
  710. #endif /* not used */
  711.  
  712. static void print_table(this_plot, plot_num)
  713. struct curve_points *this_plot;
  714. int plot_num;
  715. {
  716.     int             i, curve;
  717.  
  718.     for (curve = 0; curve < plot_num;
  719.      curve++, this_plot = this_plot->next_cp) {
  720.     fprintf(outfile, "#Curve %d, %d points\n#x y type\n", curve, this_plot->p_count);
  721.     for (i = 0; i < this_plot->p_count; i++) {
  722.         fprintf(outfile, "%g %g %c\n",
  723.             this_plot->points[i].x,
  724.             this_plot->points[i].y,
  725.             this_plot->points[i].type == INRANGE ? 'i'
  726.             : this_plot->points[i].type == OUTRANGE ? 'o'
  727.             : 'u');
  728.     }
  729.     fprintf(outfile, "\n");
  730.     }
  731.     fprintf(outfile, "\n"); /* two blank lines between plots in table output */
  732.     fflush(outfile);
  733. }
  734.  
  735. /*
  736.  * This parses the plot command after any range specifications. To support
  737.  * autoscaling on the x axis, we want any data files to define the x range,
  738.  * then to plot any functions using that range. We thus parse the input
  739.  * twice, once to pick up the data files, and again to pick up the functions.
  740.  * Definitions are processed twice, but that won't hurt.
  741.  * div - okay, it doesn't hurt, but every time an option as added for
  742.  * datafiles, code to parse it has to be added here. Change so that
  743.  * we store starting-token in the plot structure.
  744.  */
  745. static void eval_plots()
  746. {
  747.     register int    i;
  748.     register struct curve_points *this_plot, **tp_ptr;
  749.     register int    start_token, end_token;
  750.     register int    begin_token;
  751.  
  752.     int            some_functions=0;
  753.     int             plot_num, line_num, point_num, xparam = 0;
  754.     char           *xtitle;
  755.  
  756.     int x_axis = FIRST_X_AXIS,  y_axis = FIRST_Y_AXIS;
  757.  
  758.     int uses_axis[AXIS_ARRAY_SIZE];
  759.  
  760.     uses_axis[FIRST_X_AXIS] =
  761.     uses_axis[FIRST_Y_AXIS] =
  762.     uses_axis[SECOND_X_AXIS] =
  763.     uses_axis[SECOND_Y_AXIS] = 0;
  764.     
  765.     /* Reset first_plot. This is usually done at the end of this function.
  766.        If there is an error within this function, the memory is left allocated,
  767.        since we cannot call cp_free if the list is incomplete. Making sure that
  768.        the list structure is always vaild requires some rewriting */
  769.     first_plot=NULL;
  770.  
  771.     tp_ptr = &(first_plot);
  772.     plot_num = 0;
  773.     line_num = 0;        /* default line type */
  774.     point_num = 0;        /* default point type */
  775.  
  776.     xtitle = NULL;
  777.  
  778.     begin_token = c_token;
  779.  
  780.     /*** First Pass: Read through data files ***
  781.      * This pass serves to set the xrange and to parse the command, as well
  782.      * as filling in every thing except the function data. That is done after
  783.      * the xrange is defined.
  784.      */
  785.     while (TRUE) {
  786.     if (END_OF_COMMAND)
  787.         int_error("function to plot expected", c_token);
  788.  
  789.     start_token = c_token;
  790.  
  791.     if (almost_equals(c_token, "fir$st") || equals(c_token, "x1y1")) {
  792.         if (parametric && xparam)
  793.         int_error("previous parametric function not fully specified",
  794.                   c_token);
  795.         x_axis=FIRST_X_AXIS;
  796.         y_axis=FIRST_Y_AXIS;
  797.         ++c_token;
  798.     } else if (almost_equals(c_token, "sec$ond") || equals(c_token, "x2y2")) {
  799.         /* we dont set uses_second_axes yet, since they may be lying ! */
  800.         if (parametric && xparam)
  801.         int_error("previous parametric function not fully specified",
  802.                   c_token);
  803.         x_axis=SECOND_X_AXIS;
  804.         y_axis=SECOND_Y_AXIS;
  805.         ++c_token;
  806.     } else if (equals(c_token, "x1y2")) {
  807.         if (parametric && xparam)
  808.         int_error("previous parametric function not fully specified",
  809.                   c_token);
  810.         x_axis=FIRST_X_AXIS;
  811.         y_axis=SECOND_Y_AXIS;
  812.         ++c_token;
  813.     } else if (equals(c_token, "x2y1")) {
  814.         if (parametric && xparam)
  815.         int_error("previous parametric function not fully specified",
  816.                   c_token);
  817.         x_axis=SECOND_X_AXIS;
  818.         y_axis=FIRST_Y_AXIS;
  819.         ++c_token;
  820.     } else if (is_definition(c_token)) {
  821.         define();
  822.     } else {
  823.         plot_num++;
  824.  
  825.         if (isstring(c_token)) {    /* data file to plot */
  826.             int specs;
  827.             
  828.         if (parametric && xparam)
  829.             int_error("previous parametric function not fully specified",
  830.                   c_token);
  831.  
  832.         if (!(uses_axis[x_axis]&1) && autoscale_lx) {
  833.             if (auto_array[x_axis] & 1)
  834.                 min_array[x_axis] = VERYLARGE;
  835.             if (auto_array[x_axis] & 2)
  836.                 max_array[x_axis] = -VERYLARGE;
  837.         }
  838.  
  839.         uses_axis[x_axis] |= 1; /* separate record of datafile and func */
  840.         uses_axis[y_axis] |= 1;
  841.  
  842.         if (*tp_ptr)
  843.             this_plot = *tp_ptr;
  844.         else {        /* no memory malloc()'d there yet */
  845.             this_plot = cp_alloc(MIN_CRV_POINTS);
  846.             *tp_ptr = this_plot;
  847.         }
  848.         this_plot->plot_type = DATA;
  849.         this_plot->plot_style = data_style;
  850.         this_plot->plot_smooth = NONE;
  851.         this_plot->x_axis = x_axis;
  852.         this_plot->y_axis = y_axis;
  853.  
  854.         specs = df_open(NCOL);  /* up to NCOL cols */
  855.         /* this parses data-file-specific modifiers only */
  856.         /* we'll sort points when we know style, if necessary */
  857.         this_plot->token = end_token = c_token-1;  /* include modifiers in default title */
  858.  
  859.         if (datatype[x_axis]==TIME) {
  860.             if (specs < 2)
  861.                 int_error("Need full using spec for x time data", c_token);
  862.             df_timecol[0]=1;
  863.         }
  864.         
  865.         if (datatype[y_axis]==TIME) {
  866.             if (specs < 1)
  867.                 int_error("Need using spec for y time data", c_token);
  868.             df_timecol[y_axis]=1;  /* need other cols, but I'm lazy */
  869.         }
  870.         
  871.         } else {
  872.  
  873.         /* function to plot */
  874.  
  875.         uses_axis[x_axis] |= 2; /* separate record of data and func */
  876.         uses_axis[y_axis] |= 2;
  877.         some_functions=1;
  878.         if (parametric)    /* working on x parametric function */
  879.             xparam = 1 - xparam;
  880.         if (*tp_ptr) {
  881.             this_plot = *tp_ptr;
  882.             cp_extend(this_plot, samples + 1);
  883.         } else {    /* no memory malloc()'d there yet */
  884.             this_plot = cp_alloc(samples + 1);
  885.             *tp_ptr = this_plot;
  886.         }
  887.         this_plot->plot_type = FUNC;
  888.         this_plot->plot_style = func_style;
  889.         this_plot->x_axis = x_axis;
  890.         this_plot->y_axis = y_axis;
  891.         dummy_func = &plot_func;
  892.         plot_func.at = temp_at();
  893.         dummy_func = NULL;
  894.         /* ignore it for now */
  895.         end_token = c_token - 1;
  896.     } /* end of IS THIS A FILE OR A FUNC block */
  897.     
  898.     /*  deal with smooth */
  899.     if (almost_equals(c_token,"s$mooth")) {
  900.         
  901.         if (END_OF_COMMAND)
  902.           int_error("expecting smooth parameter", c_token);
  903.         else {
  904.         c_token++;
  905.         if (almost_equals(c_token,"u$nique"))
  906.             this_plot->plot_smooth = UNIQUE;
  907.         else if (almost_equals(c_token,"a$csplines"))
  908.             this_plot->plot_smooth = ACSPLINES;
  909.         else if (almost_equals(c_token,"c$splines"))
  910.             this_plot->plot_smooth = CSPLINES;
  911.         else if (almost_equals(c_token,"b$ezier"))
  912.             this_plot->plot_smooth = BEZIER;
  913.         else if (almost_equals(c_token,"s$bezier"))
  914.             this_plot->plot_smooth = SBEZIER;
  915.         else int_error("expecting 'unique', 'acsplines', 'csplines', 'bezier' or 'sbezier'", c_token);
  916.         }
  917.         this_plot->plot_style = LINES;
  918.         c_token++;    /* skip format */
  919.     }
  920.  
  921.     if (almost_equals(c_token, "t$itle")) {
  922.         if (parametric) {
  923.             if (xparam)
  924.             int_error(
  925.                      "\"title\" allowed only after parametric function fully specified",
  926.                      c_token);
  927.             else if (xtitle != NULL)
  928.             xtitle[0] = '\0';    /* Remove default title . */
  929.         }
  930.         c_token++;
  931.         if (isstring(c_token)) {
  932.             m_quote_capture(&(this_plot->title), c_token, c_token);
  933.         } else {
  934.             int_error("expecting \"title\" for plot", c_token);
  935.         }
  936.         c_token++;
  937.     } else if (almost_equals(c_token, "not$itle")) {
  938.         if (xtitle != NULL)
  939.             xtitle[0] = '\0';
  940.             c_token++;
  941.     } else {
  942.         m_capture(&(this_plot->title), start_token, end_token);
  943.         if (xparam)
  944.             xtitle = this_plot->title;
  945.     }
  946.  
  947.  
  948.     if (almost_equals(c_token, "w$ith")) {
  949.         if (parametric && xparam)
  950.             int_error("\"with\" allowed only after parametric function fully specified",
  951.                   c_token);
  952.         this_plot->plot_style = get_style();
  953.     }
  954.  
  955.             this_plot->line_type = line_num;
  956.             this_plot->point_type = point_num;
  957.  
  958.         if (!equals(c_token, ",") && !END_OF_COMMAND) {
  959.         struct value    t;
  960.         /* try to reduce confusion - set both linetype and
  961.          * pointtype here
  962.          */
  963.         this_plot->point_type =
  964.         this_plot->line_type = (int) real(const_express(&t)) - 1;
  965.         }
  966.         if (!equals(c_token, ",") && !END_OF_COMMAND) {
  967.         struct value    t;
  968.         this_plot->point_type = (int) real(const_express(&t)) - 1;
  969.         }
  970.         if ((this_plot->plot_style == POINTSTYLE) ||
  971.         (this_plot->plot_style == LINESPOINTS) ||
  972.                 (this_plot->plot_style == YERRORBARS) ||
  973.                 (this_plot->plot_style == XERRORBARS) ||
  974.                 (this_plot->plot_style == XYERRORBARS) ||
  975.                 (this_plot->plot_style == BOXXYERROR))
  976.         if (!xparam)
  977.             point_num++;
  978.         if (!xparam)
  979.         line_num++;
  980.  
  981.         if (this_plot->plot_type == DATA)
  982.         {
  983.             /* actually get the data now */
  984.             get_data(this_plot);
  985.  
  986.             /* sort */
  987.                 switch(this_plot->plot_smooth){   /* sort and average, if */
  988.                    case UNIQUE:                   /* the style requires   */
  989.                    case CSPLINES:
  990.                    case ACSPLINES:
  991.                    case SBEZIER:  sort_points(this_plot);
  992.                                   cp_implode(this_plot);
  993.                   break;
  994.            default:
  995.                     ;      /* keep gcc -Wall happy */
  996.                 }
  997.                 switch(this_plot->plot_smooth){   /* create new data set     */
  998.                    case SBEZIER:                  /* by evaluation of        */
  999.                    case BEZIER:                   /* interpolation routines  */
  1000.                    case ACSPLINES:
  1001.                    case CSPLINES: gen_interp(this_plot);
  1002.             break;
  1003.            default:
  1004.                        ; /* keep gcc -Wall happy */
  1005.                 }
  1006.  
  1007.                 /* now that we know the plot style, adjust the x- and yrange */
  1008.                 /* adjust_range(this_plot); no longer needed */
  1009.         }
  1010.         
  1011.         this_plot->token = c_token;  /* save end of plot for second pass */
  1012.         tp_ptr = &(this_plot->next_cp);
  1013.     }
  1014.  
  1015.     if (equals(c_token, ","))
  1016.         c_token++;
  1017.     else
  1018.         break;
  1019.     }
  1020.  
  1021.     if (parametric && xparam)
  1022.     int_error("parametric function not fully specified", NO_CARET);
  1023.  
  1024.  
  1025.     /*** Second Pass: Evaluate the functions ***/
  1026.     /*
  1027.      * Everything is defined now, except the function data. We expect no
  1028.      * syntax errors, etc, since the above parsed it all. This makes the code
  1029.      * below simpler. If autoscale_ly, the yrange may still change.
  1030.      * we stored last token of each plot, so we dont need to do everything again
  1031.      */
  1032.  
  1033.     /* give error if xrange badly set from missing datafile error
  1034.      * parametric or polar fns can still affect x ranges
  1035.      */
  1036.  
  1037.      if (!parametric && !polar) {
  1038.     if (min_array[FIRST_X_AXIS] == VERYLARGE ||
  1039.         max_array[FIRST_X_AXIS] == -VERYLARGE)
  1040.         int_error("x range is invalid", c_token);
  1041.     /* check that xmin -> xmax is not too small */
  1042.     FIXUP_RANGE(FIRST_X_AXIS, x);
  1043.  
  1044.     if (uses_axis[SECOND_X_AXIS] & 1) {
  1045.         /* some data plots with x2 */
  1046.         if (min_array[SECOND_X_AXIS] == VERYLARGE ||
  1047.                 max_array[SECOND_X_AXIS] == -VERYLARGE)
  1048.             int_error("x2 range is invalid", c_token);
  1049.         /* check that x2min -> x2max is not too small */
  1050.         FIXUP_RANGE(SECOND_X_AXIS, x);
  1051.         } else if (auto_array[SECOND_X_AXIS]) {
  1052.         /* copy x1's range */
  1053.         if (auto_array[SECOND_X_AXIS] & 1)
  1054.             min_array[SECOND_X_AXIS]=min_array[FIRST_X_AXIS];
  1055.         if (auto_array[SECOND_X_AXIS] & 2)
  1056.             max_array[SECOND_X_AXIS]=max_array[FIRST_X_AXIS];
  1057.     }
  1058.     }
  1059.  
  1060.     
  1061.   if (some_functions) {
  1062.  
  1063.     /* call the controlled variable t, since x_min can also mean smallest x */
  1064.     double t_min, t_max, t_step;
  1065.  
  1066.     if (parametric || polar) {
  1067.     if (!(uses_axis[FIRST_X_AXIS]&1)) {
  1068.         /* these have not yet been set to full width */
  1069.         if (auto_array[FIRST_X_AXIS] & 1) min_array[FIRST_X_AXIS] = VERYLARGE;
  1070.         if (auto_array[FIRST_X_AXIS] & 2) max_array[FIRST_X_AXIS] = -VERYLARGE;
  1071.     }
  1072.     if (!(uses_axis[SECOND_X_AXIS]&1)) {
  1073.         if (auto_array[SECOND_X_AXIS] & 1) min_array[SECOND_X_AXIS] = VERYLARGE;
  1074.         if (auto_array[SECOND_X_AXIS] & 2) max_array[SECOND_X_AXIS] = -VERYLARGE;
  1075.     }
  1076.     }
  1077.     
  1078.     x_axis=FIRST_X_AXIS; y_axis=FIRST_Y_AXIS;
  1079.     
  1080.     /* controlled variable range is going to change when we change axes.
  1081.      * but almost all plots will be just one axis.
  1082.      * so do it once here, then redo it at first or second command
  1083.      * make a macro to avoid duplicated code
  1084.      */
  1085.  
  1086. #define SET_DUMMY_RANGE(AXIS) \
  1087. do{ assert(!polar && !parametric); \
  1088.  if (log_array[AXIS]) {\
  1089.   if (min_array[AXIS] <= 0.0 || max_array[AXIS] <= 0.0)\
  1090.    int_error("x/x2 range must be greater than 0 for log scale!", NO_CARET);\
  1091.   t_min = log(min_array[AXIS])/log_base_array[AXIS]; t_max = log(max_array[AXIS])/log_base_array[AXIS];\
  1092.  } else {\
  1093.   t_min = min_array[AXIS]; t_max = max_array[AXIS];\
  1094.  }\
  1095.  t_step = (t_max - t_min) / (samples - 1); \
  1096. }while(0)
  1097.  
  1098.     if (parametric || polar) {
  1099.         t_min = min_array[T_AXIS];
  1100.         t_max = max_array[T_AXIS];
  1101.         t_step = (t_max-t_min) /  (samples-1);
  1102.     } else {
  1103.     SET_DUMMY_RANGE(FIRST_X_AXIS);
  1104.     }
  1105.     
  1106.     tp_ptr = &(first_plot);
  1107.     plot_num = 0;
  1108.     this_plot = first_plot;
  1109.     c_token = begin_token;    /* start over */
  1110.  
  1111.     /* Read through functions */
  1112.     while (TRUE) {
  1113.     if (almost_equals(c_token, "fir$st") || equals(c_token, "x1y1")) {
  1114.         if (parametric && xparam)
  1115.         int_error("previous parametric function not fully specified",
  1116.                   c_token);
  1117.         x_axis=FIRST_X_AXIS;
  1118.         y_axis=FIRST_Y_AXIS;
  1119.         ++c_token;
  1120.         /* set trange to first axis range */
  1121.         if (!polar && !parametric)
  1122.         SET_DUMMY_RANGE(FIRST_X_AXIS);
  1123.     } else if (almost_equals(c_token, "sec$ond") || equals(c_token, "x2y2")) {
  1124.         if (parametric && xparam)
  1125.         int_error("previous parametric function not fully specified",
  1126.                   c_token);
  1127.         x_axis=SECOND_X_AXIS;
  1128.         y_axis=SECOND_Y_AXIS;
  1129.         ++c_token;
  1130.         /* set trange for second axis */
  1131.         if (!polar && !parametric)
  1132.         SET_DUMMY_RANGE(SECOND_X_AXIS);
  1133.     } else if (equals(c_token, "x1y2")) {
  1134.         if (parametric && xparam)
  1135.         int_error("previous parametric function not fully specified",
  1136.                   c_token);
  1137.         x_axis=FIRST_X_AXIS;
  1138.         y_axis=SECOND_Y_AXIS;
  1139.         ++c_token;
  1140.         /* set trange for first axis */
  1141.         if (!polar && !parametric)
  1142.         SET_DUMMY_RANGE(FIRST_X_AXIS);
  1143.     } else if (equals(c_token, "x2y1")) {
  1144.         if (parametric && xparam)
  1145.         int_error("previous parametric function not fully specified",
  1146.                   c_token);
  1147.         x_axis=SECOND_X_AXIS;
  1148.         y_axis=FIRST_Y_AXIS;
  1149.         ++c_token;
  1150.         /* set trange for first axis */
  1151.         if (!polar && !parametric)
  1152.         SET_DUMMY_RANGE(SECOND_X_AXIS);
  1153.     } else if (is_definition(c_token)) {
  1154.         define();
  1155.     } else {
  1156.         plot_num++;
  1157.         if (!isstring(c_token))  {   /* function to plot */
  1158.         if (parametric) {    /* toggle parametric axes */
  1159.             xparam = 1 - xparam;
  1160.         }
  1161.         dummy_func = &plot_func;
  1162.         plot_func.at = temp_at();    /* reparse function */
  1163.  
  1164.         for (i = 0; i < samples; i++) {
  1165.             double temp;
  1166.             struct value a;
  1167.             double t = t_min + i * t_step;
  1168.            /* parametric/polar => NOT a log quantity */
  1169.             double x = (!parametric && !polar && log_array[x_axis]) ? pow(base_array[x_axis], t) : t;
  1170.             (void) Gcomplex(&plot_func.dummy_values[0], x, 0.0);
  1171.             evaluate_at(plot_func.at, &a);
  1172.  
  1173.             if (undefined || (fabs(imag(&a)) > zero)) {
  1174.             this_plot->points[i].type = UNDEFINED;
  1175.             continue;
  1176.             }
  1177.  
  1178.             temp = real(&a);
  1179.  
  1180.             this_plot->points[i].z = -1.0;  /* width of box not specified */
  1181.             this_plot->points[i].type = INRANGE;  /* for the moment */
  1182.  
  1183.             if (polar && parametric) {
  1184.             /* we cannot do range-checking now */
  1185.             /* DO NOT TAKE LOGS YET - do it in parametric_fixup */
  1186.                 this_plot->points[i].x = t; /* ignored, actually... */
  1187.                 this_plot->points[i].y = temp;
  1188.             } else {
  1189.             if (polar) {
  1190.                 double y;
  1191.                 if ( !(autoscale_r&2) && temp>rmax)
  1192.                     this_plot->points[i].type=OUTRANGE;
  1193.                 if ( !(autoscale_r&1))
  1194.                     temp -= rmin;
  1195.                 y = temp * sin(x * ang2rad);
  1196.                 x = temp * cos(x * ang2rad);
  1197.                 temp=y;
  1198.                 STORE_WITH_LOG_AND_FIXUP_RANGE(this_plot->points[i].x, x, this_plot->points[i].type,
  1199.                   x_axis, NOOP, goto come_here_if_undefined);
  1200.             } else {
  1201.                 /* if parametric, x is ignored anyway. If non-para, it must be INRANGE */
  1202.                     this_plot->points[i].x = t; /* logscale ? log(x) : x */
  1203.             }
  1204.  
  1205.             STORE_WITH_LOG_AND_FIXUP_RANGE(this_plot->points[i].y, temp, this_plot->points[i].type,
  1206.                 y_axis + (x_axis-y_axis)*xparam, NOOP, goto come_here_if_undefined);
  1207.  
  1208.             come_here_if_undefined: /* could not use a continue in this case */
  1209.             ; /* ansi requires a statement after a label */
  1210.             }
  1211.         }
  1212.         this_plot->p_count = i;    /* samples */
  1213.         }
  1214.  
  1215.         c_token = this_plot->token;  /* skip all modifers func / whole of data plots */
  1216.  
  1217.         tp_ptr = &(this_plot->next_cp);    /* used below */
  1218.         this_plot = this_plot->next_cp;
  1219.     }
  1220.  
  1221.     if (equals(c_token, ","))
  1222.         c_token++;
  1223.     else
  1224.         break;
  1225.     }
  1226.  
  1227.     if (parametric) {
  1228.     /* Now actually fix the plot pairs to be single plots */
  1229.     /* also fixes up polar&¶metric fn plots */
  1230.     parametric_fixup(first_plot, &plot_num);
  1231.     /* we omitted earlier check for range too small */
  1232.     FIXUP_RANGE(FIRST_X_AXIS, x);
  1233.     if (uses_axis[SECOND_X_AXIS]) {
  1234.          FIXUP_RANGE(SECOND_X_AXIS, x2);
  1235.     }
  1236.     }
  1237.  
  1238.   }  /* some_functions */
  1239.  
  1240.     /* throw out all curve_points at end of list, that we don't need  */
  1241.     cp_free(*tp_ptr);
  1242.     *tp_ptr = NULL;
  1243.  
  1244.     
  1245.     /* if first_plot is NULL, we have no functions or data at all. This can
  1246.        happen, if you type "plot x=5", since x=5 is a variable assignment */
  1247.  
  1248.     if (plot_num==0 || first_plot==NULL) {
  1249.     int_error("no functions or data to plot", c_token);
  1250.     }
  1251.  
  1252.     if (uses_axis[FIRST_X_AXIS]) {
  1253.     if (max_array[FIRST_X_AXIS] == -VERYLARGE ||
  1254.         min_array[FIRST_X_AXIS] ==  VERYLARGE)
  1255.        int_error("all points undefined!", NO_CARET);
  1256.     FIXUP_RANGE_FOR_LOG(FIRST_X_AXIS, x);
  1257.     }
  1258.  
  1259.     if (uses_axis[SECOND_X_AXIS]) {
  1260.     if (max_array[SECOND_X_AXIS] == -VERYLARGE ||
  1261.         min_array[SECOND_X_AXIS] ==  VERYLARGE)
  1262.        int_error("all points undefined!", NO_CARET);
  1263.     FIXUP_RANGE_FOR_LOG(SECOND_X_AXIS, x2);
  1264.     } else {
  1265.         assert(uses_axis[FIRST_X_AXIS]);
  1266.     if (auto_array[SECOND_X_AXIS]&1) min_array[SECOND_X_AXIS]=min_array[FIRST_X_AXIS];
  1267.     if (auto_array[SECOND_X_AXIS]&2) max_array[SECOND_X_AXIS]=max_array[FIRST_X_AXIS];
  1268.     }
  1269.  
  1270.     if (!uses_axis[FIRST_X_AXIS]) {
  1271.         assert(uses_axis[SECOND_X_AXIS]);
  1272.     if (auto_array[FIRST_X_AXIS]&1) min_array[FIRST_X_AXIS]=min_array[SECOND_X_AXIS];
  1273.     if (auto_array[FIRST_X_AXIS]&2) max_array[FIRST_X_AXIS]=max_array[SECOND_X_AXIS];
  1274.     }
  1275.  
  1276.  
  1277.     if (uses_axis[FIRST_Y_AXIS]) {
  1278.     if (max_array[FIRST_Y_AXIS] == -VERYLARGE ||
  1279.         min_array[FIRST_Y_AXIS] ==  VERYLARGE)
  1280.        int_error("all points undefined!", NO_CARET);
  1281.     FIXUP_RANGE(FIRST_Y_AXIS, y);
  1282.     FIXUP_RANGE_FOR_LOG(FIRST_Y_AXIS, y);
  1283.     } /* else we want to copy y2 range, but need to fix it up first */
  1284.  
  1285.     if (uses_axis[SECOND_Y_AXIS]) {
  1286.     if (max_array[SECOND_Y_AXIS] == -VERYLARGE ||
  1287.         min_array[SECOND_Y_AXIS] ==  VERYLARGE)
  1288.        int_error("all points undefined!", NO_CARET);
  1289.     FIXUP_RANGE(SECOND_Y_AXIS, y2);
  1290.     FIXUP_RANGE_FOR_LOG(SECOND_Y_AXIS, y2);
  1291.     } else {
  1292.         assert(uses_axis[FIRST_Y_AXIS]);
  1293.     if (auto_array[SECOND_Y_AXIS]&1) min_array[SECOND_Y_AXIS]=min_array[FIRST_Y_AXIS];
  1294.     if (auto_array[SECOND_Y_AXIS]&2) max_array[SECOND_Y_AXIS]=max_array[FIRST_Y_AXIS];
  1295.     }
  1296.  
  1297.     if (!uses_axis[FIRST_Y_AXIS]) {
  1298.         assert(uses_axis[SECOND_Y_AXIS]);
  1299.     if (auto_array[FIRST_Y_AXIS]&1) min_array[FIRST_Y_AXIS]=min_array[SECOND_Y_AXIS];
  1300.     if (auto_array[FIRST_Y_AXIS]&2) max_array[FIRST_Y_AXIS]=max_array[SECOND_Y_AXIS];
  1301.     }
  1302.  
  1303.     if (plot_token != -1) {
  1304.     /* note that m_capture also frees the old replot_line */
  1305.         m_capture(&replot_line, plot_token, c_token);
  1306.         plot_token = -1;        
  1307.     }
  1308.   
  1309.     if (strcmp(term->name, "table") == 0)
  1310.     print_table(first_plot, plot_num);
  1311.     else
  1312.     /* do_plot now uses max_array[], etc */
  1313.     do_plot(first_plot, plot_num);
  1314.     cp_free(first_plot);
  1315.     first_plot = NULL;
  1316. } /* eval_plots */
  1317.  
  1318.  
  1319.  
  1320.  
  1321. static void 
  1322. parametric_fixup(start_plot, plot_num)
  1323.     struct curve_points *start_plot;
  1324.     int            *plot_num;
  1325. /*
  1326.  * The hardest part of this routine is collapsing the FUNC plot types in the
  1327.  * list (which are garanteed to occur in (x,y) pairs while preserving the
  1328.  * non-FUNC type plots intact.  This means we have to work our way through
  1329.  * various lists.  Examples (hand checked): start_plot:F1->F2->NULL ==>
  1330.  * F2->NULL start_plot:F1->F2->F3->F4->F5->F6->NULL ==> F2->F4->F6->NULL
  1331.  * start_plot:F1->F2->D1->D2->F3->F4->D3->NULL ==> F2->D1->D2->F4->D3->NULL
  1332.  * 
  1333.  */
  1334. {
  1335.     struct curve_points *xp, *new_list=NULL, *free_list=NULL;
  1336.     struct curve_points **last_pointer = &new_list;
  1337.     int             i, tlen, curve;
  1338.     char           *new_title;
  1339.  
  1340.     /*
  1341.      * Ok, go through all the plots and move FUNC types together.  Note: this
  1342.      * originally was written to look for a NULL next pointer, but gnuplot
  1343.      * wants to be sticky in grabbing memory and the right number of items in
  1344.      * the plot list is controlled by the plot_num variable.
  1345.      * 
  1346.      * Since gnuplot wants to do this sticky business, a free_list of
  1347.      * curve_points is kept and then tagged onto the end of the plot list as
  1348.      * this seems more in the spirit of the original memory behavior than
  1349.      * simply freeing the memory.  I'm personally not convinced this sort of
  1350.      * concern is worth it since the time spent computing points seems to
  1351.      * dominate any garbage collecting that might be saved here...
  1352.      */
  1353.     new_list = xp = start_plot;
  1354.     curve = 0;
  1355.  
  1356.     while (++curve <= *plot_num) {
  1357.       if (xp->plot_type == FUNC) {
  1358.     /* Here's a FUNC parametric function defined as two parts. */
  1359.     struct curve_points *yp = xp->next_cp;
  1360.  
  1361.     --(*plot_num);
  1362.  
  1363.     assert(xp->p_count == yp->p_count);
  1364.     assert(xp->x_axis == yp->x_axis);
  1365.     assert(xp->y_axis == yp->y_axis);
  1366.  
  1367.     /*
  1368.      * Go through all the points assigning the y's from xp to be the x's
  1369.      * for yp. In polar mode, we need to check max's and min's as we go.
  1370.      */
  1371.  
  1372.     for (i = 0; i < yp->p_count; ++i) {
  1373.         if (polar) {
  1374.             double r=yp->points[i].y;
  1375.             double t=xp->points[i].y * ang2rad;
  1376.             double x,y;
  1377.             if ( !(autoscale_r&2) && r>rmax)
  1378.                 yp->points[i].type=OUTRANGE;
  1379.             if ( !(autoscale_r&1) )
  1380.                 r -= rmin; /* store internally as if plotting r(t)-rmin */
  1381.            x = r * cos(t);
  1382.            y = r * sin(t);
  1383.         /* we hadn't done logs when we stored earlier */
  1384.         STORE_WITH_LOG_AND_FIXUP_RANGE(yp->points[i].x, x, yp->points[i].type,
  1385.                 xp->x_axis, NOOP, NOOP);
  1386.         STORE_WITH_LOG_AND_FIXUP_RANGE(yp->points[i].y, y, yp->points[i].type,
  1387.                 xp->y_axis, NOOP,NOOP);
  1388.         } else {
  1389.         yp->points[i].x = xp->points[i].y;
  1390.  
  1391.         /* a bit lazy - check for increasing order of severity */
  1392.         assert (INRANGE < OUTRANGE && OUTRANGE < UNDEFINED);
  1393.  
  1394.         /* now use worst point type */
  1395.         if (yp->points[i].type < xp->points[i].type)
  1396.             yp->points[i].type = xp->points[i].type;
  1397.         }
  1398.     }
  1399.  
  1400.     /* Ok, fix up the title to include both the xp and yp plots. */
  1401.     if (xp->title && xp->title[0] != '\0' && yp->title) {
  1402.         tlen = strlen(yp->title) + strlen(xp->title) + 3;
  1403.         new_title = alloc((unsigned long) tlen, "string");
  1404.         strcpy(new_title, xp->title);
  1405.         strcat(new_title, ", ");    /* + 2 */
  1406.         strcat(new_title, yp->title);    /* + 1 = + 3 */
  1407.         free(yp->title);
  1408.         yp->title = new_title;
  1409.     }
  1410.  
  1411.     /* move xp to head of free list */
  1412.     xp->next_cp = free_list;
  1413.     free_list = xp;
  1414.  
  1415.     /* append yp to new_list */
  1416.     *last_pointer = yp;
  1417.     last_pointer = &(yp->next_cp);
  1418.     xp = yp->next_cp;
  1419.  
  1420.       } else {  /* data plot */
  1421.     assert(*last_pointer == xp);
  1422.     last_pointer = &(xp->next_cp);
  1423.     xp = xp->next_cp;
  1424.       }
  1425.     } /* loop over plots */
  1426.  
  1427.     first_plot = new_list;
  1428.  
  1429.     /* Ok, stick the free list at the end of the curve_points plot list. */
  1430.     *last_pointer = free_list;
  1431. }
  1432.